﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;

namespace Engine.NetClasses
{
    public class AsyncClient : Engine.NetClasses.IAsyncClient
    {
        private Socket m_socket;
        private uint m_id;
        private object locker=new object();
        private object lockerServer = new object();
        public object Locker
        {
            get
            {
                return locker;
            }
        }
        public uint ID
        {
            get { return m_id; }
            set { m_id = value; }
        }
        public Socket Socket
        {
            get { return m_socket; }
            set { m_socket = value; }
        }
        DataReader _reader;
        long _next;
        bool _ping;
        int _pingTime;
        ulong sessionKey;
        bool _needDisconect=false;
        List<PacketsBilder> fromServer = new List<PacketsBilder>(0);
        List<PacketsBilder> fromClient = new List<PacketsBilder>(0);
        object _clientObj;
        public PacketsBilder[] GetFromClient()
        {

            PacketsBilder[] tmp;
            lock (locker)
            {
                tmp = fromClient.ToArray();
                fromClient.Clear();
                fromClient.TrimExcess();
                fromClient = new List<PacketsBilder>(0);
            }
            return tmp;

        }
        public void SetFromClient(PacketsBilder FromClient)
        {


            lock (locker)
            {

                fromClient.Add(FromClient);
            }


        }
        public PacketsBilder[] GetFromServer()
        {

            PacketsBilder[] tmp;
            lock (lockerServer)
            {
                tmp = fromServer.ToArray();
                fromServer.Clear();
            }
            return tmp;

        }
        public void SetFromServer(PacketsBilder FromServer)
        {


            lock (lockerServer)
            {

                fromServer.Add(FromServer);
            }


        }
        public AsyncClient() : this(null, 0) { }
        public AsyncClient(Socket socket, uint id)
        {
            m_socket = socket;
            m_id = id;
            _reader = new DataReader();

        }
        public long nextTimePing
        {
            get
            {
                return _next;
            }
            set
            {
                _next = value;
            }
        }
        public bool Ping
        {
            get
            {
                return _ping;
            }
            set
            {
                _ping = value;
            }
        }
        public int PingTime
        {
            get
            {
                return _pingTime;
            }
            set
            {
                _pingTime = value;
            }
        }        
        public DataReader Reader
        {
            get { return _reader; }
            set { _reader = value; }
        }
        public int totalRead = 0;
        public void Read(SocketAsyncEventArgs e)
        {
            byte[][] tmp = null ;
            try
            {
                tmp= _reader.read(e.Buffer, e.Offset, e.BytesTransferred, e.Count);
            }
            catch (Exception ex)
            {

                m_server.ServerLog.WriteLineLog(TypeLog.StateLog, "Error read buffer data from client: ID='" + ID + "'");
                m_server.ServerLog.WriteLineLog(TypeLog.StateLog, "Client ID='"+ID+"' Exception: " + ex.ToString());

            }
            
            if (tmp != null)
            {
                for (int i = 0; i < tmp.Length; i++)
                {
                    if (NetPacket.GetPacket(tmp[i][3]).DoubleCrypt)
                    {
                        try
                        {
                        PacketsBilder pb = new PacketsBilder(tmp[i], 0,_CR);
                        checkPack(pb);
                        SetFromClient(pb);
                        m_server.ServerLog.WriteLineLog(TypeLog.ReciveLog, "Packet:'" + ((IPacket)pb.getStryct()).Name + "' from client: ID='" + ID+"'");
                        }
                        catch (Exception ex)
                        {

                            m_server.ServerLog.WriteLineLog(TypeLog.StateLog, "Error create packet from client: ID='" + ID + "'");
                            m_server.ServerLog.WriteLineLog(TypeLog.StateLog, "Client ID='"+ID+"' Exception: " + ex.ToString());
                        }
                        
                    }
                    else
                    {
                        try
                        {
                            PacketsBilder pb = new PacketsBilder(tmp[i], 0);
                            checkPack(pb);
                            SetFromClient(pb);
                            m_server.ServerLog.WriteLineLog(TypeLog.ReciveLog, "Packet:'" + ((IPacket)pb.getStryct()).Name + "' from client: ID='" + ID+"'");
                        }
                        catch (Exception ex)
                        {

                            m_server.ServerLog.WriteLineLog(TypeLog.StateLog, "Error create packet from client: ID='"+ID+"'");
                            m_server.ServerLog.WriteLineLog(TypeLog.StateLog, "Client ID='"+ID+"' Exception: " + ex.ToString());
                        }
                    }
                   
                  
                    
                }
                if (onDataRead!=null)
                {
                    onDataRead(this);
                }
               // totalRead += tmp.Length;
             //   Console.WriteLine("from Client id {0} ip:{1}", m_id, m_socket.RemoteEndPoint.ToString());
             //   Console.WriteLine("recive in one request {0}  total read pack{1}",  tmp.Length,totalRead);
            }
          //  Console.WriteLine("Total pack from klient {0} in one request {1}", fromClient.Count, tmp.Length);
        }
        private void checkPack(PacketsBilder pb)
        {
            IPacket packet = pb.getStryct();
            if (packet.PacketType == 5)
            {
                
                    this.Ping = true;
                    this.PingTime = ((NetPing)packet).Ping;
                    this._needDisconect = false;                  
                 
            }
        }
        public bool needDisconect
        {
            get
            {
                return _needDisconect;
            }
            set
            {
                _needDisconect=value;
            }
        }
        

        public event DataRead onDataRead;


        public ulong SessionKey
        {
            get
            {
                return sessionKey;
            }
            set
            {
               sessionKey=value;
            }
        }


        public int CountFromClient
        {
            get
            {
                int c=0;
                lock (locker)
                {
                    c = fromClient.Count;
                }
                return c;
            }
        }

        public int CountFromServer
        {
            get {
                int c = 0;
                lock (lockerServer)
                {
                    c = fromServer.Count;
                }
                return c;
            }
        }
        Helpers.BlowFish _CR;
        public Helpers.BlowFish CR
        {
            get { return _CR; }
            set { _CR = value; }
        }


        public object ClientObject
        {
            get
            {
               return _clientObj;
            }
            set
            {
                _clientObj=value;
            }
        }

        BaseServer m_server;
        public BaseServer Server
        {
            get
            {
               return m_server;
            }
            set
            {
                m_server =value;
            }
        }
    }
}
